#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <signal.h>
#include <functional>
#include "log.hpp"
#include "Protocol.hpp"

using namespace std;

namespace server
{
  enum
  {
    USAGE_ERR = 1,
    SOCKET_ERR,
    BIND_ERR,
    LISTEN_ERR
  };
  // 构建函数的指针
  typedef std::function<bool(const httpRequest &req, httpResponse &resp)> func_t; // 用于传回调函数

  static const uint16_t gport = 8080;
  static const int gbacklog = 5;
  // static const std::string ip="0.0.0.0";
  class Calserver
  {
  public:
    Calserver(func_t func_, const uint16_t &port = gport) : func(func_), _listensock(-1), _port(port) {}

    void Handlerhttp(int sock) // 放类外面为了解耦，可以更改方法
    {                          // 1.保证消息完整性：读取
      char buffer[4096];
      httpRequest req;
      httpResponse resp;
      ssize_t n = recv(sock, buffer, sizeof(buffer), 0); // 保证读到完整的http请求
      if (n > 0)
      {
        buffer[n] = 0;
        req.message = buffer;
        req.parse();                                                     // 反序列化
        func(req, resp);                                                 // 回调函数
        send(sock, resp.outmessage.c_str(), sizeof(resp.outmessage), 0); // 序列化后的回复
      }
    }
    void initServer()
    { // 1.创建套接字
      _listensock = socket(AF_INET, SOCK_STREAM, 0);
      if (_listensock < 0)
      {
        logMessage(FATAL, "create socket error");
        exit(SOCKET_ERR);
      }
      logMessage(NORMAL, "create socket success");
      // 2.绑定服务端的网络信息到结构体上
      struct sockaddr_in local;
      memset(&local, 0, sizeof(local));
      local.sin_family = AF_INET;
      local.sin_port = htons(_port);
      local.sin_addr.s_addr = INADDR_ANY; // 任意ip
      if (bind(_listensock, (struct sockaddr *)&local, sizeof(local)) < 0)
      {
        logMessage(FATAL, "bind socket error");
        exit(BIND_ERR);
      }
      logMessage(NORMAL, "bind socket success");
      // 3.设置套接字为监听状态
      if (listen(_listensock, gbacklog) < 0)
      {
        logMessage(FATAL, "listen socket error");
        exit(LISTEN_ERR);
      }
      logMessage(NORMAL, "listensocket success");
    }
    void start()
    {
      for (;;)
      {
        // 4.获取链接
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        // 建立链接是在accept之前，客户端os发出链接请求，服务端os接受
        int sock = accept(_listensock, (struct sockaddr *)&peer, &len); // sock为得到客户端传递信息的文件描述符
        if (sock < 0)
        {
          logMessage(ERROR, "accept error, next");
          continue;
        }
        logMessage(NORMAL, "accept success 文件描述符：%d", sock);
        logMessage(ERROR, "accept error, next");
        logMessage(FATAL, "fatal error, next");
        logMessage(DEBUG, "测试 error, next");
        logMessage(WARNING, "警告, next");
        logMessage(ERROR, "错误, next");

        int n = fork();
        if (n == 0)
        {
          close(_listensock);
          Handlerhttp(sock);
          close(sock);
          exit(0);
        }
        close(sock);
      }
    }

    ~Calserver() {}

  private:
    int _listensock;
    uint16_t _port;
    func_t func;
  };

}
